package com.djl.zenithbite.service.shopping.cart.impl;

import com.djl.zenithbite.common.request.BaseRequest;
import com.djl.zenithbite.common.response.BaseResponse;
import com.djl.zenithbite.common.threadlocal.UserContextHolder;
import com.djl.zenithbite.dto.request.shopping.cart.CartItemRequest;
import com.djl.zenithbite.dto.request.shopping.order.OrderItemRequest;
import com.djl.zenithbite.dto.response.cart.CartItemVO;
import com.djl.zenithbite.dto.response.cart.CartResponse;
import com.djl.zenithbite.entity.*;
import com.djl.zenithbite.repository.CartMapper;
import com.djl.zenithbite.repository.ProductMapper;
import com.djl.zenithbite.repository.StoreMapper;
import com.djl.zenithbite.service.shopping.cart.CartService;
import com.djl.zenithbite.util.check.AssertUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private CartMapper cartMapper;

    @Autowired
    private ProductMapper productMapper;

    @Autowired
    private StoreMapper storeMapper;


    @Override
    public BaseResponse<List<CartResponse>> list() {

        List<CartResponse> cartInfoList = getCartInfoList();

        BaseResponse<List<CartResponse>> response = new BaseResponse<>();
        response.setCode(BaseResponse.SUCCESS);
        response.setData(cartInfoList);

        return response;
    }

    private List<CartResponse> getCartInfoList(){

        Map<Integer,List<CartItemVO>> storeCartMap = new HashMap<>();
        Map<Integer,Store> storeMap = new HashMap<>();

        Integer userId = UserContextHolder.getUserPrimaryId();

        CartExample cartExample = new CartExample();
        CartExample.Criteria cartExampleCriteria = cartExample.createCriteria();
        cartExampleCriteria.andUserIdEqualTo(userId);

        List<Cart> carts = cartMapper.selectByExample(cartExample);

        Optional.ofNullable(carts).orElse(new ArrayList<>()).forEach(cart -> {
            Integer productId = cart.getProductId();
            Product product = productMapper.selectByPrimaryKey(productId);
            Store store = storeMapper.selectByPrimaryKey(product.getStoreId());
            List<CartItemVO> cartList = storeCartMap.getOrDefault(store.getStoreId(), new ArrayList<>());
            CartItemVO cartItemVO = new CartItemVO();
            cartItemVO.setCart(cart);
            cartItemVO.setProduct(product);
            cartList.add(cartItemVO);
            storeCartMap.put(store.getStoreId(),cartList);
            storeMap.put(store.getStoreId(),store);
        });

        return storeCartMap.entrySet().stream().map(entry -> {
            CartResponse response = new CartResponse();
            response.setStore(storeMap.get(entry.getKey()));
            response.setCartList(entry.getValue());
            return response;
        }).collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse<CartResponse> add(CartItemRequest request) {
        Product product = productMapper.selectByPrimaryKey(request.getProductId());

        CartExample cartExample = new CartExample();
        CartExample.Criteria criteria = cartExample.createCriteria();
        criteria.andProductIdEqualTo(request.getProductId());
        criteria.andUserIdEqualTo(UserContextHolder.getUserPrimaryId());
        List<Cart> carts = cartMapper.selectByExample(cartExample);

        if (CollectionUtils.isEmpty(carts)){
            Cart cart = generateCart(request, product);
            cartMapper.insertSelective(cart);
        }else {
            Cart cart = carts.get(0);
            cart.setQuantity(cart.getQuantity() + request.getOrderNum());
            cartMapper.updateByPrimaryKeySelective(cart);
        }
        return storeCart(product.getStoreId());
    }

    public Cart generateCart(CartItemRequest request,Product product){
        Cart cart = new Cart();
        cart.setUserId(UserContextHolder.getUserPrimaryId());
        cart.setProductId(request.getProductId());
        cart.setQuantity(request.getOrderNum());
        cart.setPrice(product.getProductPrice());
        cart.setTotalPrice(product.getProductPrice().multiply(new BigDecimal(String.valueOf(request.getOrderNum()))));
        cart.setCreatedAt(new Date());
        cart.setUpdatedAt(new Date());
        return cart;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public BaseResponse<CartResponse> edit(CartItemRequest request) {
        Product product = productMapper.selectByPrimaryKey(request.getProductId());

        Cart cart = cartMapper.selectByPrimaryKey(request.getCartId());
        AssertUtil.notNull(cart,"cart can not be null!!!");

        if (request.getOrderNum() == 0){
            cartMapper.deleteByPrimaryKey(request.getCartId());
        }else {
            Cart updateCart = generateCart(request, product);

            updateCart.setCartId(request.getCartId());

            cartMapper.updateByPrimaryKeySelective(updateCart);
        }

        return storeCart(product.getStoreId());
    }

    @Override
    public BaseResponse<CartResponse> storeCart(Integer storeId) {
        List<CartResponse> cartInfoList = getCartInfoList();
        Optional<CartResponse> first = cartInfoList.stream().filter(cartResponse -> Objects.equals(cartResponse.getStore().getStoreId(), storeId)).findFirst();
        BaseResponse<CartResponse> response = new BaseResponse();
        response.setData(first.orElse(null));
        response.setCode(BaseResponse.SUCCESS);
        return response;
    }
}
